package kibahed.uni.mdp.rlalgorithms;

import java.text.DecimalFormat;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;

import kibahed.uni.mdp.representation.Action;
import kibahed.uni.mdp.representation.MDPField;
import kibahed.uni.mdp.representation.Position;
import kibahed.uni.mdp.representation.State;

public class MeanTimeToAbsorbtion extends ARLalgorithm {

	private Map<State, Double> T;

	public MeanTimeToAbsorbtion(MDPField mdpField) {
		super(mdpField);
		createT();
		
	}

	private void createT() {
		T = new HashMap<State, Double>();
		for (State s : mdpField.getStateList()) {
			T.put(s, 0.);
		}
	}

	@Override
	public void calculate() {

		int it = 0;
		HashMap<State, Double> Tk;
		do {

			Tk = new HashMap<State, Double>(T);

			for (State currentState : mdpField.getStateList()) {

				double min = Double.MAX_VALUE;
				Action chosenAction = null;
				for (Action action : currentState.getActions()) {

					double sum = 0;

					for (Entry<Action, Double> entry : currentState
							.getProbailitiesForAction(action).entrySet()) {
						
						double probabilityOfNextAction = entry.getValue();
						Action nextActionOfCurrentState = entry.getKey();
						
						sum += probabilityOfNextAction * Tk.get(currentState.getAimStateForAction(nextActionOfCurrentState));
						
					}

					if (sum < min) {
						min = sum;
						chosenAction = action;
					}
				}

				if (currentState.isAbsorbing()) {
					T.put(currentState, 0.);
					policy.put(currentState, chosenAction);
				} else {
					T.put(currentState, min + 1);
					policy.put(currentState, chosenAction);
				}
			}
			it++;
			
		} while (!convergationReached(Tk, 0.00001));

//		System.out.println("needed " + it + " iterations to convergate");
		print();
	}

	private boolean convergationReached(HashMap<State, Double> oldT,
			double epsilon) {
		int count = 0;
		for (State s : T.keySet()) {

			if ((Math.abs(T.get(s) - oldT.get(s)) < epsilon && T.get(s) != 1)) {
				count++;
			}
		}
		if (count == oldT.keySet().size()) {
			return true;
		}
		return false;
	}

	@Override
	public void calculate(Position startPosition) {

	}

	private void print() {
		
		System.out.println("------------------------------------------------------------- \n" +
				"RESULT FOR MEAN TIME TO ABSORBITON \n" +
				"--------------------------------------------------------------\n");
		DecimalFormat df = new DecimalFormat();
		df.setMaximumFractionDigits(2);
		for (int i = 0; i < mdpField.getStateList().size(); i++) {
			State s = mdpField.getStateList().get(i);
			System.out.print(" | [" + s.getPosition().getRow() + ","
					+ s.getPosition().getCollum() + "] T = "
					+ df.format(T.get(s)));
			if ((i + 1) % (mdpField.getCollums()) == 0 && i != 0) {
				System.out.println("\n");
			}
		}
		System.out.print("|");
	}

	private void printPolicy() {
		DecimalFormat df = new DecimalFormat();
		df.setMaximumFractionDigits(2);
		for (int i = 0; i < mdpField.getStateList().size(); i++) {
			State s = mdpField.getStateList().get(i);
			System.out.print(" | [" + s.getPosition().getRow() + ","
					+ s.getPosition().getCollum() + "] : Action = "
					+ policy.get(s).getActionName());
			if ((i + 1) % (mdpField.getCollums()) == 0 && i != 0) {
				System.out.println("\n");
			}
		}
		System.out.print("|");
	}
}
